package setting

import (
	"bytes"
	_ "embed"
	"fmt"
	"gitee.com/jikey/elk-blog/pkg/file"
	"github.com/fsnotify/fsnotify"
	"github.com/spf13/viper"
	"io"
	"os"
	"path/filepath"

	// "gopkg.in/ini.v1"
	"log"
)

var (
	// Config *ini.File

	// PageSize RunMode string
	PageSize int
	// Site     *SiteMap
)

// AllConfig 读取配置文件config
type AllConfig struct {
	Redis     string
	Database  DatabaseConfig
	App       AppConfig
	Site      SiteMap
	Server    ServerConfig
	Security  SecurityConfig
	Xorm      XormConfig
	Sensitive SensitiveConfig
	Search    SearchConfig
	Aliyun    AliyunConfig
}

type DatabaseConfig struct {
	Type        string
	Host        string
	Port        string
	User        string
	Password    string
	DbName      string
	Charset     string
	TablePrefix string `toml:"table_prefix" mapstructure:"table_prefix"`
	MaxIdle     int    `toml:"max_idle" mapstructure:"max_idle"`
	MaxConn     int    `toml:"max_conn" mapstructure:"max_conn"`
}

type AliyunConfig struct {
	AccessKey       string `toml:"access_key" mapstructure:"access_key"`
	SecretAccessKey string `toml:"secret_access_key" mapstructure:"secret_access_key"`
	BucketName      string `toml:"bucket_name" mapstructure:"bucket_name"`
	Endpoint        string
	InnerNet        string `toml:"inner_net" mapstructure:"inner_net"`
	OuterNet        string `toml:"outer_net" mapstructure:"outer_net"`
	AliyunNet       string `toml:"aliyun_net" mapstructure:"aliyun_net"`
}

type AppConfig struct {
	Env          string
	LogLevel     string
	CookieSecret string
	DataPath     string
	PageSize     int `toml:"page_size" mapstructure:"page_size"`
	Key          string
	UploadOss    bool   `toml:"upload_oss" mapstructure:"upload_oss"`
	LogFilePath  string `toml:"log_file_path" mapstructure:"log_file_path"`
	LogFileName  string `toml:"log_file_name" mapstructure:"log_file_name"`
	StaticDomain string `toml:"static_domain" mapstructure:"static_domain"`
}

type ServerConfig struct {
	Host          string
	Port          string
	ReaderTimeout int
	WriteTimeout  int
}
type SecurityConfig struct {
	UnsubscribeTokenKey string
	ActivateSignSalt    string
}

type XormConfig struct {
	ShowSql  bool
	LogLevel int
}
type SensitiveConfig struct {
	Title   string
	Content string
}
type SearchConfig struct {
	EngineUrl string
}

type SiteMap struct {
	Domain      string
	Title       string
	Keyword     string
	Description string
	Slogon      Slogon
	Email       string
	Contact     string
	Company     string
	Record      string
	Phone       string
	Icp         string
	Address     string
	Tpl         string
}

type Slogon struct {
	blogTitle       string
	blogKeywords    string
	blogDescription string
}

func init() {
	LoadInI()
	SetApp()
	SetMeta()
	SetSite()
}

var (
	//go:embed config.toml
	devConfig []byte
	Config    = new(AllConfig)
)

// LoadInI 载入配置
func LoadInI() {
	var r io.Reader

	r = bytes.NewReader(devConfig)

	viper.SetConfigType("toml")

	if err := viper.ReadConfig(r); err != nil {
		panic(err)
	}

	if err := viper.Unmarshal(Config); err != nil {
		fmt.Println(err)
		panic(err)
	}

	viper.SetConfigName("config")
	viper.AddConfigPath("./setting")

	configFile := "./setting/" + "config.toml"
	_, ok := file.IsExists(configFile)
	if !ok {
		if err := os.MkdirAll(filepath.Dir(configFile), 0766); err != nil {
			panic(err)
		}

		f, err := os.Create(configFile)
		if err != nil {
			panic(err)
		}
		defer f.Close()

		if err := viper.WriteConfig(); err != nil {
			panic(err)
		}
	}

	viper.WatchConfig()
	viper.OnConfigChange(func(e fsnotify.Event) {
		if err := viper.Unmarshal(Config); err != nil {
			panic(err)
		}
	})
}

// LoadInIOld 载入配置
func LoadInIOld() {
	var err error
	path, _ := os.Getwd()
	cfg := viper.New()
	cfg.SetConfigName("config") // 配置文件的文件名，没有扩展名，如 .yaml, .toml 这样的扩展名
	cfg.SetConfigType("toml")   // 设置扩展名。在这里设置文件的扩展名。另外，如果配置文件的名称没有扩展名，则需要配置这个选项
	// viper.AddConfigPath("/etc/appname/")  // 查找配置文件所在路径
	// viper.AddConfigPath("$HOME/.appname") // 多次调用AddConfigPath，可以添加多个搜索路径
	// cfg.AddConfigPath(path + "/config") // 还可以在工作目录中搜索配置文件
	// cfg.AddConfigPath(path + "/config") // 还可以在工作目录中搜索配置文件
	path_ := filepath.Join(path, "/setting")
	fmt.Println(path_)
	cfg.AddConfigPath(path_) // 还可以在工作目录中搜索配置文件
	err = cfg.ReadInConfig() // 搜索并读取配置文件

	if err != nil { // 处理错误
		// panic(fmt.Errorf("Fatal error config file: %s \n", err))
		log.Fatalf("Fatal error config file: %v", err)
	}
	err = cfg.Unmarshal(&Config)
	if err != nil {
		return
	}
	viper.WatchConfig()
	// 将配置文件绑定到config上
	// Config, err = ini.Load("config/env.ini")
	// // Config, err = ini.Load("env.ini")
	// if err != nil {
	//	log.Fatalf("Fail to parse 'conf/env.ini': %v", err)
	// }
}

func SetApp() {
	// sec := config.App
	PageSize = Config.App.PageSize
}

func SetMeta() {
	// sec := Config.Section("site")
	_ = viper.GetString("site.keyword")
}

func SetSite() {
	// Site = &SiteMap{}
	// Site := config.Site
	// _ = Config.Section("site").MapTo(Site)
}
